package com.example.testsbjenkins.CompletableFuture;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StopWatch;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author: lt
 * @date: 2022/7/29 11:30
 * @Description: for循环调用远程接口 更改为 通过CompletableFuture 并发访问接口
 */
@Slf4j
public class CompletableFutureListHandlerTest {

    static final String url = "http://10.100.37.28:9994/auth-center/auth/getUserSession?token=36efd0731b544e7d80c8b5564ad935ec";

    static final ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();;
    private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 100, 3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(512));


    public static class OutDto{
         Integer id;
         String content;

        public OutDto() {
        }

        public OutDto(Integer id, String content) {
            this.id = id;
            this.content = content;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }
    }
    /**
     * 通过for循环 批量执行
     * @return
     */
    public static String testByForCost(){
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        List<OutDto> outDtoList = new ArrayList<>();
        StopWatch watch = new StopWatch();
        watch.start();
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
        for (Integer i : list) {
            OutDto out = new OutDto();
            String content = postRequest();
            out.setId(i);
            out.setContent(content);
            outDtoList.add(out);
        }
        String result = JSONUtil.toJsonStr(outDtoList);
        watch.stop();
        System.out.println("耗时:"+watch.getTotalTimeMillis()+"ms");
        System.out.println("结果是:"+result);
        return result;
    }

    
    static String postRequest(){
        log.debug("线程名: "+Thread.currentThread().getName());
        RestTemplate template = new RestTemplate();
        // 封装参数，千万不要替换为Map与HashMap，否则参数无法传递
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
        //paramMap.add("token", "52729df9abf04db1a16e8143080a3da2");
        // 1、使用postForObject请求接口
        String result = template.postForObject(url, paramMap, String.class);
        System.out.println("result1==================" + result);
        return result;
    }
    /**
     * 通过线程池执行
     * @return
     */
    public static String testByExecutorsCost() throws ExecutionException, InterruptedException {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        ExecutorService executorService = Executors.newFixedThreadPool(list.size());
        List<OutDto> outDtoList = new ArrayList<>();
        StopWatch watch = new StopWatch();
        watch.start();

        List<Future<String>>  futureList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            Future<String> future = executorService.submit(() -> postRequest());
            futureList.add(future);
        }
        for (Integer i : list) {
            OutDto out = new OutDto();
            out.setId(i);
            outDtoList.add(out);
        }         

        for (int i = 0; i < futureList.size(); i++) {
            String s = futureList.get(i).get();
            outDtoList.get(i).setContent(s);
        }
       
        String result = JSONUtil.toJsonStr(outDtoList);
        watch.stop();
        executorService.shutdown();
        System.out.println("耗时:"+watch.getTotalTimeMillis()+"ms");
        System.out.println("结果是:"+result);
        return result;
    }

    /**
     * 通过Future 和 Executors 异步执行
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static String testByFutureAndExecutorsCost() throws ExecutionException, InterruptedException {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        StopWatch watch = new StopWatch();
        watch.start();
        taskExecutor.setCorePoolSize(5);
        //线程池维护线程的最大数量,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        taskExecutor.setMaxPoolSize(10);
        //缓存队列
        taskExecutor.setQueueCapacity(20);
        //允许的空闲时间,当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        taskExecutor.setKeepAliveSeconds(60);
        //线程名称前缀
        taskExecutor.setThreadNamePrefix("zhx-moon-thread-");
        // 线程池对拒绝任务（无线程可用）的处理策略，目前只支持AbortPolicy、CallerRunsPolicy；默认为后者
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 调度器shutdown被调用时等待当前被调度的任务完成
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        // 等待时长
        taskExecutor.setAwaitTerminationSeconds(60);
        taskExecutor.initialize();
        
        List<OutDto> outDtoList = new ArrayList<>();
        List<String> contentList = new ArrayList<>();
        List<Future<String>> result = new ArrayList<>();
        for (Integer i : list) {
            Future<?> submit = taskExecutor.submit(() -> {
                postRequest();
            });
            result.add((Future<String>) submit);
            OutDto out = new OutDto();
            out.setId(i);
            outDtoList.add(out);
        }
        for (Future<String> stringFuture : result) {
            contentList.add(stringFuture.get());
        }

        for (int i = 0; i < outDtoList.size(); i++) {
            outDtoList.get(i).setContent(contentList.get(i));
        }
        
        String res = JSONUtil.toJsonStr(outDtoList);
        taskExecutor.shutdown();
        watch.stop();
        System.out.println("耗时:"+watch.getTotalTimeMillis()+"ms");
        System.out.println("结果是:"+res);
        return res;
    }


    /**
     * 通过CompletableFuture 和 Executors 批量执行任务
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static String testByCompletableFutureAndExecutorsCost() throws ExecutionException, InterruptedException {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        StopWatch watch = new StopWatch();
        watch.start();

        List<CompletableFuture> futureList = new ArrayList<>();

        List<OutDto> outDtoList = new ArrayList<>();
        for (Integer i : list) {
            OutDto out = new OutDto();
            out.setId(i);
            CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> postRequest(),executor);
            futureList.add(completableFuture);
            outDtoList.add(out);
        }

        CompletableFuture.allOf(futureList.toArray(new  CompletableFuture[futureList.size()])).join();
        for (int i = 0; i < list.size(); i++) {
            outDtoList.get(i).setContent(futureList.get(i).get().toString());

        }
        String res = JSONUtil.toJsonStr(outDtoList);
        watch.stop();
        System.out.println("耗时:"+watch.getTotalTimeMillis()+"ms");
        System.out.println("结果是:"+res);
        return res;
    }


    /**
     * 
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static String testByParallelStreamCost() throws ExecutionException, InterruptedException {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        StopWatch watch = new StopWatch();
        watch.start();
        List<OutDto> outDtoList = new ArrayList<>();
        list.stream().parallel().forEach(i->{
            OutDto out = new OutDto();
            out.setId(i);
            out.setContent(postRequest());
            outDtoList.add(out);
        });
        
        String res = JSONUtil.toJsonStr(outDtoList);
        watch.stop();
        System.out.println("耗时:"+watch.getTotalTimeMillis()+"ms");
        System.out.println("结果是:"+res);
        return res;
    }
    

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //testByCompletableFutureAndExecutorsCost();
        //testByForCost();
        //testByExecutorsCost();
        testByFutureAndExecutorsCost();
        //testByParallelStreamCost();
    }
    
    
    
}
